package com.study.lxy.security.sm2;

import com.study.lxy.security.SM2Key;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.BigIntegers;
import org.junit.Test;

import java.io.IOException;
import java.math.BigInteger;

public class SM2Utils2 {

    private static SM2 sm2 = SM2.newInstance();

    public static SM2Key generateKeyPair2(){
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

        SM2Key sm2Key = new SM2Key();
        ECPoint normalize = publicKey.normalize();
        sm2Key.setPubKeyX(ByteUtils.toHexString(normalize.getXCoord().getEncoded()));
        sm2Key.setPubKeyY(ByteUtils.toHexString(normalize.getYCoord().getEncoded()));
        sm2Key.setPrivateKey(ByteUtils.toHexString(privateKey.toByteArray()));
        return sm2Key;
    }

    public static String encrypt(String pubKeyX, String pubKeyY, String data){

        byte[] dataBytes = data.getBytes();

        byte[] source = new byte[dataBytes.length];
        System.arraycopy(dataBytes, 0, source, 0, dataBytes.length);

        BigInteger x = BigIntegers.fromUnsignedByteArray(ByteUtils.fromHexString(pubKeyX));
        BigInteger y = BigIntegers.fromUnsignedByteArray(ByteUtils.fromHexString(pubKeyY));
        ECPoint pubKey = sm2.ecc_curve.validatePoint(x,y);

        Cipher cipher = new Cipher();
        ECPoint c1 = cipher.init_enc(sm2, pubKey);

        cipher.encrypt(source);
        byte[] c3 = new byte[32];
        cipher.doFinal(c3);

        //C1 C2 C3拼装成加密字串
        return ByteUtils.toHexString(c1.getEncoded()) + ByteUtils.toHexString(source) + ByteUtils.toHexString(c3);
    }

    public static String decrypt(String privateKey, String data) throws IOException{
        byte[] byteData = ByteUtils.fromHexString(data);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = ByteUtils.fromHexString(data.substring(0,130));
        int c2Len = byteData.length - 97;
        byte[] c2 = ByteUtils.fromHexString(data.substring(130,130 + 2 * c2Len));
        byte[] c3 = ByteUtils.fromHexString(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));


        BigInteger userD = new BigInteger(1, ByteUtils.fromHexString(privateKey));
        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.init_dec(userD, c1);
        cipher.decrypt(c2);
        cipher.doFinal(c3);
        //返回解密结果
        return new String(c2);
    }


    public static void main(String[] args) throws Exception {
        String data = "123456";
        SM2Key key = SM2Utils2.generateKeyPair2();
        System.out.println("generate keys = " + key);
        System.out.println("data before encrypt : " + data);
        String cipherText = SM2Utils2.encrypt(key.getPubKeyX(), key.getPubKeyY(), data);
        System.out.println("data after encrypt : " + cipherText);
        String dataDecrypt = SM2Utils2.decrypt(key.getPrivateKey(), cipherText);
        System.out.println("data after decrypt : " + dataDecrypt);
    }
}
